use crate::segment::Segment;
use crate::size_class::PageKind;

pub struct SegmentQueue {
    first: *mut Segment,
    last: *mut Segment,
    page_kind: PageKind,
}

impl SegmentQueue {
    pub fn new(page_kind: PageKind) -> Self {
        SegmentQueue {
            first: std::ptr::null_mut(),
            last: std::ptr::null_mut(),
            page_kind,
        }
    }

    pub fn push_front(&mut self, segment: *mut Segment) {
        unsafe {
            (*segment).set_next(self.first);
            (*segment).set_prev(std::ptr::null_mut());

            if !self.first.is_null() {
                (*self.first).set_prev(segment);
            } else {
                // If queue was empty, update last
                self.last = segment;
            }
            self.first = segment;
        }
    }

    pub fn push_back(&mut self, segment: *mut Segment) {
        unsafe {
            (*segment).set_prev(self.last);
            (*segment).set_next(std::ptr::null_mut());

            if !self.last.is_null() {
                (*self.last).set_next(segment);
            } else {
                // If queue was empty, update first
                self.first = segment;
            }
            self.last = segment;
        }
    }

    pub fn remove(&mut self, segment: *mut Segment) {
        unsafe {
            if (*segment).get_prev().is_null() {
                self.first = (*segment).get_next();
            } else {
                (*(*segment).get_prev()).set_next((*segment).get_next());
            }

            if (*segment).get_next().is_null() {
                self.last = (*segment).get_prev();
            } else {
                (*(*segment).get_next()).set_prev((*segment).get_prev());
            }

            (*segment).set_prev(std::ptr::null_mut());
            (*segment).set_next(std::ptr::null_mut());
        }
    }

    pub fn is_empty(&self) -> bool {
        self.first.is_null()
    }

    pub fn iter(&self) -> SegmentQueueIterator {
        SegmentQueueIterator {
            current: self.first,
        }
    }

    pub fn find_free_segment(&mut self) -> Option<&mut Segment> {
        let mut current = self.first;
        while !current.is_null() {
            unsafe {
                let segment = &mut *current;
                if segment.has_free() {
                    return Some(segment);
                }
                current = segment.get_next();
            }
        }
        None
    }

    pub fn get_page_kind(&self) -> PageKind {
        self.page_kind
    }
}

pub struct SegmentQueueIterator {
    current: *mut Segment,
}

impl Iterator for SegmentQueueIterator {
    type Item = *mut Segment;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current.is_null() {
            None
        } else {
            let segment = self.current;
            unsafe {
                self.current = (*segment).get_next();
            }
            Some(segment)
        }
    }
}
